/*
  tex.cpp - class texture
*/

#include <windows.h>
#include "tex.h"
#include <gl/gl.h>

void inittex ()
{
  glEnable (GL_TEXTURE_2D);
}

static void deletetex (unsigned int *tex)
{
    glDeleteTextures (1, tex);
}

texture::texture ()
{
  tex = 0;
}

texture::~texture ()
{
  deletetex (&tex);
}

void texture::unload ()
{
  if (tex)
    deletetex (&tex);
  tex = 0;
}

// --------------------------------------------- png --
#include "png.h"
#include "maths.h"
#include <stdio.h>
#include <stdlib.h>

#define PNG_HEADER_SIZE 8

typedef struct {
    unsigned  width;
    unsigned  height;
    void     *data;
} Image;

static Image load_png_image(const char *name, int keep_rgb = 1, int keep_alpha = 1, int pixel_size = 4)
{
    Image image = { 0, 0, NULL };

    FILE *PNG_file = fopen(name, "rb");
    if (PNG_file == NULL)
    {
        //fprintf(stderr, "Can't open PNG file %s\n", name);
        return image;
    }
    
    GLubyte PNG_header[PNG_HEADER_SIZE];
    
    fread(PNG_header, 1, PNG_HEADER_SIZE, PNG_file);
    if (png_sig_cmp(PNG_header, 0, PNG_HEADER_SIZE) != 0)
    {
        //fprintf(stderr, "%s is not a PNG file\n", name);
        return image;
    }
    
    png_structp PNG_reader
        = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (PNG_reader == NULL)
    {
        //fprintf(stderr, "Can't start reading PNG file %s\n", name);
        fclose(PNG_file);
        return image;
    }

    png_infop PNG_info = png_create_info_struct(PNG_reader);
    if (PNG_info == NULL)
    {
        //fprintf(stderr, "Can't get info for PNG file %s\n", name);
        png_destroy_read_struct(&PNG_reader, NULL, NULL);
        fclose(PNG_file);
        return image;
    }

    png_infop PNG_end_info = png_create_info_struct(PNG_reader);
    if (PNG_end_info == NULL)
    {
        //fprintf(stderr, "Can't get end info for PNG file %s\n", name);
        png_destroy_read_struct(&PNG_reader, &PNG_info, NULL);
        fclose(PNG_file);
        return image;
    }
    
    png_init_io(PNG_reader, PNG_file);
    png_set_sig_bytes(PNG_reader, PNG_HEADER_SIZE);
    
    png_read_info(PNG_reader, PNG_info);
    
    png_uint_32 width, height;
    width = png_get_image_width(PNG_reader, PNG_info);
    height = png_get_image_height(PNG_reader, PNG_info);
    
    png_uint_32 bit_depth, color_type;
    bit_depth = png_get_bit_depth(PNG_reader, PNG_info);
    color_type = png_get_color_type(PNG_reader, PNG_info);
    
    if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
        if (keep_rgb)
        {
            png_set_palette_to_rgb(PNG_reader);
        }
        else
        {
            //fprintf(stderr,
            //        "(%s): paletted PNG to grayscale image not supported\n",
            //        name);
            return image;
        }
    }

    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) 
    {
        png_set_gray_1_2_4_to_8(PNG_reader);
    }
    
    if (keep_rgb)
    {
        if (color_type == PNG_COLOR_TYPE_GRAY ||
            color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        {
            png_set_gray_to_rgb(PNG_reader);
        }
    }
    else
    {
        if (color_type == PNG_COLOR_TYPE_RGB ||
            color_type == PNG_COLOR_TYPE_RGB_ALPHA)
        {
            png_set_rgb_to_gray_fixed(PNG_reader, 1, 0, 0);
        }
    }

    if (keep_alpha)
    {
        if (png_get_valid(PNG_reader, PNG_info, PNG_INFO_tRNS))
        {
            png_set_tRNS_to_alpha(PNG_reader);
        }
        else
        {
            png_set_filler(PNG_reader, 0xff, PNG_FILLER_AFTER);
        }
    }
    else
    {
        if (color_type & PNG_COLOR_MASK_ALPHA)
        {
            png_set_strip_alpha(PNG_reader);
        }
    }
    
    if (bit_depth == 16)
    {
        png_set_strip_16(PNG_reader);
    }
    
    png_read_update_info(PNG_reader, PNG_info);
    
    unsigned w = wrap2n (width);
    unsigned h = wrap2n (height);
    png_byte* PNG_image_buffer = (png_byte*)malloc(pixel_size * w * h);
    png_byte** PNG_rows = (png_byte**)malloc(height * sizeof(png_byte*));
    
    unsigned int row;
    for (row = 0; row < height; ++row)
    {
        PNG_rows[height - 1 - row] = PNG_image_buffer + (row * pixel_size * width);
    }
    
    png_read_image(PNG_reader, PNG_rows);
    
    free(PNG_rows);
    
    png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info);
    fclose(PNG_file);
    
    image.width = width;
    image.height = height;
    image.data = PNG_image_buffer;
    
    return image;
}


#include <gl/glaux.h>
#include <stdlib.h>
bool texture::load (char *file)
{
  int width, height;
  void *data;
  
  if (tex) {unload ();}
#if 0
  AUX_RGBImageRec *TextureImage;
  
  TextureImage = auxDIBImageLoad (file);
  if (!file || !TextureImage) {
    tex = 0;
    return false;
  }
  
  width = TextureImage->sizeX;
  height = TextureImage->sizeY;
  data = TextureImage->data;
#else
  Image img = load_png_image (file, 1, 1, 4);
  
	if (img.data == 0)
		return false;
  twidth = width = img.width;
  theight = height = img.height;
  data = img.data;
#endif

  glGenTextures (1, &tex);
  glBindTexture (GL_TEXTURE_2D, tex);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 
      wrap2n (width), wrap2n (height), 0, 
      GL_RGBA, GL_UNSIGNED_BYTE, data);
  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  glBindTexture (GL_TEXTURE_2D, 0);
#if 0
  if (TextureImage) {
    if (TextureImage->data)
      free (TextureImage->data);
    free (TextureImage);
  }
#else
  if (img.data)
    free (img.data);
#endif

  return true;
}

void texture::bind ()
{
  glBindTexture (GL_TEXTURE_2D, tex);
}
